package com.itheima.stock.service.impl;

import com.google.common.base.Strings;
import com.itheima.stock.mapper.SysUserMapper;
import com.itheima.stock.pojo.SysUser;
import com.itheima.stock.service.UserService;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.res.LoginRespVo;
import com.itheima.stock.vo.res.R;
import com.itheima.stock.vo.res.ResponseCode;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 定义用户服务接口实现
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IdWorker idWorker;

    @Override
    public R<LoginRespVo> login(LoginReqVo vo) {

        //1.判断传入参数的合法性
        if(vo==null || Strings.isNullOrEmpty(vo.getUsername()) ||
                Strings.isNullOrEmpty(vo.getPassword()) || Strings.isNullOrEmpty(vo.getRkey()) ||
                Strings.isNullOrEmpty(vo.getCode())){
            //请求参数异常
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }

        //根据传入的rkey从redis中获取保存的验证码，然后与传入的验证码进行比对
        String rCode = (String) redisTemplate.opsForValue().get("ck:"+vo.getRkey());
        //如果rCode为null，或者不匹配，则说明rCode失效
        if(rCode == null || !rCode.equals(vo.getCode())){
            //请求参数异常
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        //如果正确则及时淘汰传入的数据，当然也可借助失效周期，自动淘汰
        redisTemplate.delete("ck:"+vo.getRkey());

        //2.根据用户名查询用户信息（包含了加密后的密文）
        SysUser userInfo=sysUserMapper.findUserByUserName(vo.getUsername());

        //3.判断对应用户是否存在，以及密码是否匹配
        //                                           这是明文密码       这是从数据库查询的来的密文密码  做判断
        if(userInfo==null || !passwordEncoder.matches(vo.getPassword(),userInfo.getPassword())){
            //判断不存才，返回:账号或密码错误
            R.error(ResponseCode.SYSTEM_PASSWORD_ERROR.getMessage());

        }

        //4.将查询的用户信息封装到loginRespVo类型的对象下
        /**
         * 我们发现存的对象中包含了响应的数据，但是不能直接返回
         *      为什么：
         *          1.不安全
         *          2.浪费网络资源（按需加载）
         */
        LoginRespVo loginRespVo = new LoginRespVo();
        //这是springboot提供的方法，将userinfo对应的信息copy到loginRespVo中
        BeanUtils.copyProperties(userInfo,loginRespVo);

        //5.组装响应对象，响应前端
        return R.ok(loginRespVo);





    }


    /**
     * 从UserService跳过来
     * 实现验证码生成
     *
     * @return
     */
    @Override
    public R<Map> generateCode() {
         //1.生成随机码，长度为4，且都为数字
        //借助Apache提供的工具类生成纯数字字符串
        String checkCode = RandomStringUtils.randomNumeric(4);
        //2.生成全局唯一id：模拟session
        String sessionID=String.valueOf(idWorker.nextId());
        //3.保存在redis中，设置失效时间：5m
        //id加前缀的业务吗，方便阅读理解和维护
        redisTemplate.opsForValue().set("ck:"+sessionID,checkCode,5, TimeUnit.MINUTES);
        //4.组装数据，响应给前端
        Map<String,String> map=new HashMap<>();
        map.put("code",checkCode);
        map.put("rkey",sessionID);
        return R.ok(map);

    }
}
